---
title: Getting Started
description: A quick tutorial to get you up and running with Plate.
---

<Callout className="my-4">
  Use our <Link href="/?builder=true" target="_blank">interactive builder</Link> to generate _personalized_ installation steps.
</Callout>

<Steps>

### Create project

You can choose one of the following templates to get started:

| Option                                                                                                             | NextJS | Tailwind | Plate | Plugins |
| ------------------------------------------------------------------------------------------------------------------ | ------ | -------- | ----- | ------- |
| <Link target="_blank" href="https://github.com/udecode/plate-playground-template">Plate playground template</Link> | ✅     | ✅       | ✅    | ✅      |
| <Link target="_blank" href="https://github.com/udecode/plate-template">Plate minimal template</Link>               | ✅     | ✅       | ✅    |         |
| <Link target="_blank" href="/docs/components/installation/next">NextJS template</Link>                             | ✅     | ✅       |       |         |

For an existing project, jump to the next step.

### Add dependencies

Install the core and the plugins you need. You need at least:

```bash
npm install @udecode/plate-common slate slate-react slate-history slate-hyperscript react react-dom
```

Alternatively you can install **`@udecode/plate`** that contains all the packages excluding the ones with heavy dependencies (e.g. **`@udecode/plate-dnd`**).

```bash
npm install @udecode/plate slate slate-react slate-history slate-hyperscript react react-dom
```

### Basic Editor

Let's start with a minimal editor setup.

```tsx showLineNumbers {4,7-9}
import { usePlateEditor, Plate, PlateContent } from '@udecode/plate-common/react';

export default function BasicEditor() {
  const editor = usePlateEditor();

  return (
    <Plate editor={editor}>
      <PlateContent placeholder="Type..." />
    </Plate>
  );
}
```

`Plate` manages the editor state and `PlateContent` renders the editor content.

<ComponentPreview name="basic-editor-default-demo" padding="md" />

### Styling

Let's give our editor some styles: [Editor](/docs/components/editor) is a styled version of `PlateContent`.

<ComponentPreview name="basic-editor-styling-demo" padding="md" />

<Callout className="mt-4">
  **Note**: `Editor` is just an example of a styled editor using Tailwind, and if you're using it, make sure to follow the installation steps in the [Manual Installation](/docs/components/installation/manual) guide. You can create your own styled version of `PlateContent`.
  <ComponentSource name="editor" />
</Callout>

### Initializing Editor's Value

Let's specify the initial content of the editor: a single paragraph.

```tsx showLineNumbers {3-12,16}
// ...

const value = [
  {
    type: 'p',
    children: [
      {
        text: 'This is editable plain text with react and history plugins, just like a <textarea>!',
      },
    ],
  },
];

export default function BasicEditor() {
  const editor = usePlateEditor({
    value,
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

<Callout className="mt-4">
  **Note**: Plate uses the **`type`** property to enable plugins to render nodes
  by type.
</Callout>

<ComponentPreview name="basic-editor-value-demo" padding="md" />

### Implementing Change Handler

At this stage, it's crucial to monitor editor modifications in order to store the values appropriately. The **`onChange`** prop will serve this purpose. You can also persist the editor's state by saving the value to local storage or a database and loading it back when needed.

```tsx showLineNumbers {4-5,8,14-16}
// ...

export default function BasicEditor() {
  const localValue =
    typeof window !== 'undefined' && localStorage.getItem('editorContent');

  const editor = usePlateEditor({
    value: localValue ? JSON.parse(localValue) : value,
  });

  return (
    <Plate
      editor={editor}
      onChange={({ value }) => {
        localStorage.setItem('editorContent', JSON.stringify(value));
      }}
    >
      <PlateContent />
    </Plate>
  );
}
```

<ComponentPreview name="basic-editor-handler-demo" padding="md" />

### Plugins

<Callout className="my-4">
  Use our <Link href="/?builder=true" target="_blank">interactive builder</Link> to pick your plugins.
</Callout>

Let's use the basic plugins for a rich-text editor.

```tsx showLineNumbers {15-23}
// ...

import { BoldPlugin, ItalicPlugin, UnderlinePlugin, CodePlugin } from '@udecode/plate-basic-marks/react';
import { HeadingPlugin } from '@udecode/plate-heading/react';
import { BlockquotePlugin } from '@udecode/plate-block-quote/react';
import { CodeBlockPlugin } from '@udecode/plate-code-block/react';

const value = [
  // ...
];

export default function BasicEditor() {
  const editor = usePlateEditor({
    value,
    plugins: [
      HeadingPlugin,
      BlockquotePlugin,
      CodeBlockPlugin,
      BoldPlugin,
      ItalicPlugin,
      UnderlinePlugin,
      CodePlugin,
    ],
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

<ComponentPreview name="basic-plugins-default-demo" padding="md" />

The plugins are functioning correctly. However, since we haven't specified any custom components for rendering, the editor is using the default (unstyled) components. Specifically, the default element component is a **`div`**, and the default leaf component is a **`span`**.

<Callout className="mt-4">
  **Note**: You don't need to add core plugins such as **`ReactPlugin`**,
  **`HistoryPlugin`** and **`ParagraphPlugin`** as **`usePlateEditor`** already does it.
</Callout>

### Components

<Callout className="mt-4">
  **Note**: Plate plugins are packaged unstyled, implying that you have complete
  control over markup and styling, hence you can integrate your own design
  system or [Plate UI](/docs/components). If using the latter, use our <Link href="/?builder=true" target="_blank">interactive builder</Link> to pick your components.
</Callout>

To plug-in all the components in one place, we can use the **`override.components`** option in **`usePlateEditor`**:

```tsx showLineNumbers {14,20-22}
// ...

// Import Prism for code highlighting
import Prism from 'prismjs';

// This is a local file, you will need to create this file in your project
import { createPlateUI } from '@/lib/create-plate-ui';

export default function BasicEditor() {
  const editor = usePlateEditor({
    plugins: [
      HeadingPlugin,
      BlockquotePlugin,
      CodeBlockPlugin.configure({ options: { prism: Prism } }),
      BoldPlugin,
      ItalicPlugin,
      UnderlinePlugin,
      CodePlugin,
    ],
    override: {
      components: createPlateUI(),
    },
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

<ComponentSource src="src/lib/plate/create-plate-ui.ts" />

<ComponentPreview name="basic-plugins-components-demo" padding="md" />

### Initializing Editor's Value with HTML String

You can also specify the initial content of the editor using an HTML string and the corresponding plugins.

```tsx showLineNumbers {3,7}
// ...

const htmlValue = '<p>This is <b>bold</b> and <i>italic</i> text!</p>';

export default function BasicEditor() {
  const editor = usePlateEditor({
    value: htmlValue,
    plugins: [
      BoldPlugin,
      ItalicPlugin,
    ],
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

### That's it!

You can now play around with the <Link href="/?builder=true">Playground</Link> and start building your own editor.

</Steps>
